/**
 * 
 */
package xiaojian.toolkit.bean.util.meta;

import java.io.IOException;
import java.util.Collection;
import java.util.List;

import org.apache.commons.collections4.Transformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;

import xiaojian.toolkit.bean.annotation.Eventable;
import xiaojian.toolkit.bean.annotation.Events;
import xiaojian.toolkit.ebus.meta.EventTypeMetainfo;
import xiaojian.toolkit.util.PackageUtils;
import xiaojian.toolkit.util.StringUtils;

/**
 * @author hp
 * 
 */
public class BeanMetainfoUtils {

	private static final Logger logger = LoggerFactory
			.getLogger(BeanMetainfoUtils.class);

	static public Int2TypeMetainfo createTypeMetainfo(
			Collection<String> packages, Transformer transformer) {
		DefaultInt2TypeMetainfo typeMetainfo = new DefaultInt2TypeMetainfo();

		if (null != packages) {
			for (String pkgName : packages) {
				try {
					String[] clsNames = PackageUtils.findClassesInPackage(
							pkgName, null, null);
					for (String clsName : clsNames) {
						try {
							ClassLoader cl = Thread.currentThread()
									.getContextClassLoader();
							if (logger.isDebugEnabled()) {
								logger.debug(
										"using ClassLoader {} to load Class {}",
										cl, clsName);
							}
							Class<?> cls = cl.loadClass(clsName);
							Integer value = (Integer) transformer
									.transform(cls);
							if (null != value) {
								typeMetainfo.add(value, cls);
								logger.info("metainfo: add " + value + ":=>"
										+ cls);
							}
						} catch (ClassNotFoundException e) {
							logger.error("createTypeMetainfo: ", e);
						}
					}
				} catch (IOException e) {
					logger.error("createTypeMetainfo: ", e);
				}
			}
		}

		return typeMetainfo;
	}

	static public Int2TypeMetainfo createTypeMetainfoByClasses(
			Collection<Class<?>> clazzes, Transformer transformer) {
		DefaultInt2TypeMetainfo typeMetainfo = new DefaultInt2TypeMetainfo();

		for (Class<?> cls : clazzes) {
			Integer value = (Integer) transformer.transform(cls);
			if (null != value) {
				typeMetainfo.add(value, cls);
			}
		}

		return typeMetainfo;
	}
	
	static public EventTypeMetainfo createEventTypeMetainfoByClasses(
			Collection<Class<?>> clazzes) {
		EventTypeMetainfo eventTypeMetaInfo = new EventTypeMetainfo();

		for (Class<?> cls : clazzes) {
			Events events = cls.getAnnotation(Events.class);
			if (events != null) {
				List<String> eventLst = Lists.newArrayList(events
						.value());
				if (!eventLst.isEmpty()) {
					eventTypeMetaInfo.add(cls, eventLst);
				}
			}
			
			Eventable eventable = cls.getAnnotation(Eventable.class);
			if (eventable != null) {
				eventTypeMetaInfo.add(cls, Lists.newArrayList("event." + cls.getName()));
			}
		}

		return eventTypeMetaInfo;
	}

	static public EventTypeMetainfo createEventTypeMetaInfoByPackages(
			Collection<String> packages) {
		EventTypeMetainfo eventTypeMetaInfo = new EventTypeMetainfo();

		if (packages == null || packages.size() == 0) {
			return eventTypeMetaInfo;
		}

		for (String pkgName : packages) {
			try {
				String[] clsNames = PackageUtils.findClassesInPackage(pkgName,
						null, null);
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				for (String clsName : clsNames) {
					if (logger.isDebugEnabled()) {
						logger.debug("using ClassLoader {} to load Class {}",
								cl, clsName);
					}
					Class<?> cls = null;
					try {
						cls = cl.loadClass(clsName);
					} catch (ClassNotFoundException e) {
						logger.error("createEventTypeMetaInfoByPackages: ", e);
						continue;
					}

					if (cls == null) {
						continue;
					}

					Events events = cls.getAnnotation(Events.class);
					if (events != null) {
						List<String> eventLst = StringUtils.stringToList(events.value());
						if (!eventLst.isEmpty()) {
							eventTypeMetaInfo.add(cls, eventLst);
						}
					}
					
					Eventable eventable = cls.getAnnotation(Eventable.class);
					if (eventable != null) {
						eventTypeMetaInfo.add(cls, Lists.newArrayList("event." + cls.getName()));
					}
				}
			} catch (IOException e) {
				logger.error("createTypeMetainfo: ", e);
			}
		}

		return eventTypeMetaInfo;

	}
}
